package com.jacky.concurrent;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * Created by jacky on 2018/2/12.
 */
public class MyLock implements Lock{
    private final Sync sync;

    /**
     * 创建公平锁或非公平锁
     * @param fairFlag
     */
    public MyLock(boolean fairFlag){
       sync = fairFlag ? new FairSync() : new NonFairSync();
    }

    /**
     * 默认是公平锁
     */
    public MyLock(){
        sync = new FairSync();
    }

    /**
     * 获取锁
     */
    @Override
    public void lock() {
         sync.acquire(1);
    }

    /**
     * 获取可中断锁
     * @throws InterruptedException
     */
    @Override
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    /**
     * 它表示用来尝试获取锁，如果获取成功，则返回true，如果获取失败（即锁已被其他线程获取），则返回false，
     * 也就说这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待
     * @return
     */
    @Override
    public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }

    /**
     * 获得可超时的锁
     * @param time
     * @param unit
     * @return
     * @throws InterruptedException
     */
    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1,unit.toNanos(time));
    }

    /**
     * 释放锁
     */
    @Override
    public void unlock() {
        sync.release(1);
    }

    @Override
    public Condition newCondition() {
        return sync.new ConditionObject();
    }

    abstract static class Sync extends AbstractQueuedSynchronizer {
        /**
         * 判断当前线程是否获得锁
         * @return
         */
        @Override
        protected boolean isHeldExclusively() {
            return Thread.currentThread() ==getExclusiveOwnerThread();
        }

        /**
         * 尝试释放锁
         * @param arg
         * @return
         */
        @Override
        protected boolean tryRelease(int arg) {
            int newState =getState()-arg;
            setState(newState < 0 ? 0:newState);
            if (newState ==0){
                setExclusiveOwnerThread(null);
            }
            return true;
        }

        final boolean nonfairTryAcquire(int arg) {
            Thread thread = Thread.currentThread();
            int state = getState();
            if (state ==0){
                compareAndSetState(0,state+arg);
                //设置独占线程
                setExclusiveOwnerThread(thread);
                return true;
            }
            if (isHeldExclusively()){
                setState(state+arg);
                return true;
            }
            return false;
        }

    }
    static class FairSync extends Sync{
        /**
         * 尝试公平锁获得锁
         * @param arg
         * @return
         */
        @Override
        public boolean tryAcquire(int arg) {
            Thread thread = Thread.currentThread();
            int state = getState();
            if (state ==0){
                //判断队列是否有数据，有数据就返回获取锁失败(公平锁才会这么做)
                if (hasQueuedPredecessors()){
                    return false;
                }
                compareAndSetState(0,state+arg);
                //设置独占线程
                setExclusiveOwnerThread(thread);
                return true;
            }
            if (isHeldExclusively()){
                setState(state+arg);
                 return true;
            }
            return false;
        }

    }

    static class NonFairSync extends Sync{
        @Override
        public boolean tryAcquire(int arg) {
            return  nonfairTryAcquire(arg);
        }
    }
}
